home *** CD-ROM | disk | FTP | other *** search
- /* Low level AX.25 frame processing - address header */
-
- #include <stdio.h>
- #include "global.h"
- #include "mbuf.h"
- #include "iface.h"
- #include "timer.h"
- #include "arp.h"
- #include "slip.h"
- #include "ax25.h"
- #include "lapb.h"
- #include "netrom.h"
- #include "ip.h"
- #include <ctype.h>
-
- static int axsend __ARGS((struct iface *iface,struct ax25_addr *dest,
- struct ax25_addr *source,char cmdrsp,char ctl,struct mbuf *data));
- static int16 ax25rhash __ARGS((struct ax25_addr *s));
-
- /* AX.25 broadcast address: "QST-0" in shifted ascii */
- static struct ax25_addr Ax25_bdcst = {
- 'Q'<<1, 'S'<<1, 'T'<<1, ' '<<1, ' '<<1, ' '<<1,
- ('0'<<1) | E,
- };
- static char Axbdcst[AXALEN]; /* Same thing, network format */
- struct ax25_addr Mycall;
- struct ax_route *Ax_routes[NAXROUTE]; /* Routing table header */
- int Digipeat = 1; /* Controls digipeating */
-
- /* Send IP datagrams across an AX.25 link */
- int
- ax_send(bp,iface,gateway,prec,del,tput,rel)
- struct mbuf *bp;
- struct iface *iface;
- int32 gateway;
- int prec;
- int del;
- int tput;
- int rel;
- {
- char *hw_addr;
- struct ax25_cb *axp;
- struct ax25_addr destaddr;
- struct mbuf *tbp;
-
- if((hw_addr = res_arp(iface,ARP_AX25,gateway,bp)) == NULLCHAR)
- return 0; /* Wait for address resolution */
-
- if(del || (!rel && (iface->flags == DATAGRAM_MODE))){
- /* Use UI frame */
- return (*iface->output)(iface,hw_addr,
- iface->hwaddr,PID_IP,bp);
- }
- /* Reliability is needed; use I-frames in AX.25 connection */
- memcpy(destaddr.call,hw_addr,ALEN);
- destaddr.ssid = hw_addr[ALEN];
-
- if((axp = find_ax25(&destaddr)) == NULLAX25){
- /* Open a new connection */
- axp = open_ax25(iface,(struct ax25_addr *)iface->hwaddr,
- (struct ax25_addr *)hw_addr,
- AX_ACTIVE,Axwindow,s_arcall,s_atcall,s_ascall,-1);
- if(axp == NULLAX25){
- free_p(bp);
- return -1;
- }
- }
- if(axp->state == DISCONNECTED){
- est_link(axp);
- lapbstate(axp,SETUP);
- }
- /* Insert the PID */
- if((tbp = pushdown(bp,1)) == NULLBUF){
- free_p(bp);
- return -1;
- }
- bp = tbp;
- bp->data[0] = PID_IP;
- if((tbp = segmenter(bp,axp->paclen)) == NULLBUF){
- free(bp);
- return -1;
- }
- return send_ax25(axp,tbp,-1);
- }
- /* Add AX.25 link header and send packet.
- * Note that the calling order here must match enet_output
- * since ARP also uses it.
- */
- int
- ax_output(iface,dest,source,pid,data)
- struct iface *iface; /* Interface to use; overrides routing table */
- char *dest; /* Destination AX.25 address (7 bytes, shifted) */
- char *source; /* Source AX.25 address (7 bytes, shifted) */
- int16 pid; /* Protocol ID */
- struct mbuf *data; /* Data field (follows PID) */
- {
- struct mbuf *bp;
-
- /* Prepend pid to data */
- bp = pushdown(data,1);
- if(bp == NULLBUF){
- free_p(data);
- return -1;
- }
- bp->data[0] = (char)pid;
- return axsend(iface,(struct ax25_addr *)dest,
- (struct ax25_addr *)source,COMMAND,UI,bp);
- }
- /* Common subroutine for sendframe() and ax_output() */
- static int
- axsend(iface,dest,source,cmdrsp,ctl,data)
- struct iface *iface; /* Interface to use; overrides routing table */
- struct ax25_addr *dest; /* Destination AX.25 address (7 bytes, shifted) */
- struct ax25_addr *source;/* Source AX.25 address (7 bytes, shifted) */
- char cmdrsp; /* Command/response indication */
- char ctl; /* Control field */
- struct mbuf *data; /* Data field (includes PID) */
- {
- struct mbuf *cbp;
- struct ax25 addr;
- struct ax_route *axr;
-
- /* If there's a digipeater route, get it */
- axr = ax_lookup((struct ax25_addr *)dest);
-
- memset((char *)&addr,0,sizeof(addr));
- ASSIGN(addr.dest,*dest);
- ASSIGN(addr.source,*source);
- addr.cmdrsp = cmdrsp;
-
- if(axr != NULLAXR){
- memcpy((char *)addr.digis,(char *)axr->digis,
- axr->ndigis*sizeof(struct ax25_addr));
- addr.ndigis = axr->ndigis;
- } else
- addr.ndigis = 0;
-
- /* Allocate mbuf for control field, and fill in */
- if((cbp = pushdown(data,1)) == NULLBUF){
- free_p(data);
- return -1;
- }
- cbp->data[0] = ctl;
-
- if((data = htonax25(&addr,cbp)) == NULLBUF){
- free_p(cbp); /* Also frees data */
- return -1;
- }
- /* This shouldn't be necessary because redirection has already been
- * done at the IP router layer, but just to be safe...
- */
- if(iface->forw != NULLIF)
- return (*iface->forw->raw)(iface->forw,data);
- else
- return (*iface->raw)(iface,data);
- }
- /* Process incoming AX.25 packets.
- * After optional tracing, the address field is examined. If it is
- * directed to us as a digipeater, repeat it. If it is addressed to
- * us or to QST-0, kick it upstairs depending on the protocol ID.
- */
- void
- ax_recv(iface,bp)
- struct iface *iface;
- struct mbuf *bp;
- {
- struct ax25_addr *ap;
- struct mbuf *hbp;
- char control;
- struct ax25 hdr;
- struct ax25_cb *axp;
- struct ax25_addr ifcall;
- struct ax_route *axr;
-
- /* Use the address associated with this iface */
- memcpy(ifcall.call,iface->hwaddr,ALEN);
- ifcall.ssid = iface->hwaddr[ALEN];
-
- /* Pull header off packet and convert to host structure */
- if(ntohax25(&hdr,&bp) < 0){
- /* Something wrong with the header */
- free_p(bp);
- return;
- }
- /* Scan, looking for our call in the repeater fields, if any.
- * Repeat appropriate packets.
- */
- for(ap = &hdr.digis[0]; ap < &hdr.digis[hdr.ndigis]; ap++){
- if(ap->ssid & REPEATED)
- continue; /* Already repeated */
- /* Check if packet is directed to us as a digipeater */
- if(Digipeat && addreq(ap,&ifcall)){
- /* Yes, kick it back out */
- ap->ssid |= REPEATED;
- if((hbp = htonax25(&hdr,bp)) != NULLBUF){
- if(iface->forw != NULLIF)
- (*iface->forw->raw)(iface->forw,hbp);
- else
- (*iface->raw)(iface,hbp);
- bp = NULLBUF;
- }
- }
- free_p(bp); /* Dispose if not forwarded */
- return;
- }
- if(bp == NULLBUF){
- /* Nothing left */
- return;
- }
- /* Sneak a peek at the control field. This kludge is necessary because
- * AX.25 lacks a proper protocol ID field between the address and LAPB
- * sublayers; a control value of UI indicates that LAPB is to be
- * bypassed.
- */
- control = *bp->data & ~PF;
- if(uchar(control) == UI){
- char pid;
-
- (void) pullchar(&bp);
- if(pullup(&bp,&pid,1) != 1)
- return; /* No PID */
- /* Handle packets. Multi-frame messages are not allowed */
- switch(uchar(pid)){
- case PID_IP:
- if(addreq(&hdr.dest,&Ax25_bdcst))
- ip_route(bp,1); /* Broadcast packet */
- else if(addreq(&hdr.dest,&ifcall))
- ip_route(bp,0); /* Packet directed at us */
- else free_p(bp);
- break;
- case PID_ARP:
- if(addreq(&hdr.dest,&ifcall)
- || addreq(&hdr.dest,&Ax25_bdcst))
- arp_input(iface,bp);
- else free_p(bp);
- break;
- case PID_NETROM:
- if(addreq(&hdr.dest,&Nr_nodebc))
- nr_nodercv(iface,&hdr.source,bp);
- else free_p(bp);
- break;
- case PID_NO_L3:
- if(addreq(&hdr.dest,&ifcall))
- beac_input(iface,&hdr.source,bp);
- else free_p(bp);
- break;
- default:
- free_p(bp);
- break;
- }
- return;
- }
- /* Everything from here down is LAPB, so drop anything that's
- * not explicitly for us ...
- */
- if(!addreq(&hdr.dest,&ifcall)){
- free_p(bp) ;
- return ;
- }
- /* If there's no locally-set entry in the routing table,
- * enter or update it. Leave local routes alone.
- */
- if((axr = ax_lookup(&hdr.source)) == NULLAXR || axr->type == AX_AUTO){
- struct ax25_addr digis[MAXDIGIS];
-
- if(hdr.ndigis > 0){
- int i,j;
- /* Construct reverse digipeater path */
- for(i=hdr.ndigis-1,j=0;i >= 0;i--,j++){
- memcpy((char *)&digis[j],(char *)&hdr.digis[i],
- sizeof(struct ax25_addr));
- digis[j].ssid &= ~(E|REPEATED);
- }
- }
- ax_add(&hdr.source,AX_AUTO,digis,hdr.ndigis);
- }
- /* Find the source address in hash table */
- if((axp = find_ax25(&hdr.source)) == NULLAX25){
- /* Create a new ax25 entry for this guy,
- * insert into hash table keyed on his address,
- * and initialize table entries
- */
- if((axp = cr_ax25(&hdr.source)) == NULLAX25){
- free_p(bp);
- return;
- }
- /* Swap source and destination */
- ASSIGN(axp->remote,hdr.source);
- ASSIGN(axp->local,hdr.dest);
- axp->iface = iface;
- }
- if(hdr.cmdrsp == UNKNOWN)
- axp->proto = V1; /* Old protocol in use */
-
- lapb_input(axp,hdr.cmdrsp,bp);
- }
- /* General purpose AX.25 frame output */
- int
- sendframe(axp,cmdrsp,ctl,data)
- struct ax25_cb *axp;
- int cmdrsp;
- int ctl;
- struct mbuf *data;
- {
- return axsend(axp->iface,&axp->remote,&axp->local,cmdrsp,ctl,data);
- }
- void
- axarp()
- {
- memcpy(Axbdcst,Ax25_bdcst.call,ALEN);
- Axbdcst[ALEN] = Ax25_bdcst.ssid;
-
- arp_init(ARP_AX25,AXALEN,PID_IP,PID_ARP,10,Axbdcst,psax25,setpath);
- }
- /* Find a route for an AX.25 address */
- struct ax_route *
- ax_lookup(target)
- struct ax25_addr *target;
- {
- register struct ax_route *axr;
-
- for(axr = Ax_routes[ax25rhash(target)]; axr != NULLAXR; axr = axr->next){
- if(addreq(&axr->target,target))
- break;
- }
- return axr;
- }
- /* Add an entry to the AX.25 routing table */
- struct ax_route *
- ax_add(target,type,digis,ndigis)
- struct ax25_addr *target;
- int type;
- struct ax25_addr digis[];
- int ndigis;
- {
- int16 hval,i;
- register struct ax_route *axr;
-
- if(ndigis < 0 || ndigis > MAXDIGIS)
- return NULLAXR;
-
- if((axr = ax_lookup(target)) == NULLAXR){
- axr = (struct ax_route *)calloc(1,sizeof(struct ax_route));
- if(axr == NULLAXR)
- return NULLAXR;
- hval = ax25rhash(target);
- axr->prev = NULLAXR;
- axr->next = Ax_routes[hval];
- if(axr->next != NULLAXR)
- axr->next->prev = axr;
- Ax_routes[hval] = axr;
- ASSIGN(axr->target,*target);
- axr->ndigis = ndigis;
- }
- axr->type = type;
- if(axr->ndigis != ndigis)
- axr->ndigis = ndigis;
-
- for(i=0;i<ndigis;i++)
- memcpy((char *)axr->digis,(char *)digis,
- ndigis*sizeof(struct ax25_addr));
- return axr;
- }
- int
- ax_drop(target)
- struct ax25_addr *target;
- {
- register struct ax_route *axr;
-
- if((axr = ax_lookup(target)) == NULLAXR)
- return -1;
-
- if(axr->next != NULLAXR)
- axr->next->prev = axr->prev;
- if(axr->prev != NULLAXR)
- axr->prev->next = axr->next;
- else
- Ax_routes[ax25rhash(target)] = axr->next;
- free((char *)axr);
- return 0;
- }
- /* Address hash function. Exclusive-ORs each byte, ignoring
- * such insignificant, annoying things as E and H bits
- */
- static int16
- ax25rhash(s)
- struct ax25_addr *s;
- {
- register char x;
- register int i;
- register char *cp;
-
- x = 0;
- cp = s->call;
- for(i=ALEN; i!=0; i--)
- x ^= *cp++ & 0xfe;
- x ^= s->ssid & SSID;
- return uchar(x) % NAXROUTE;
- }
-